Skip to content

Exercises

Pricing Woes

The solution we came up with in the previous lesson has one potential issue: if multiple plans share the same price, the price won't animate:

Update the sandbox below so that the price animates when the user changes plans, even if those plans have the same price.

Acceptance Criteria:

  • The displayed price should animate whenever the user changes the plan, even if the price doesn't change.

Code Playground

import React from 'react';

import PriceDisplay from './PriceDisplay';
import styles from './PlanSelection.module.css';

function PlanSelection({ plans }) {
const id = React.useId();
const [plan, setPlan] = React.useState(plans[0]);

return (
<>
<PriceDisplay price={plan.price} />

<fieldset className={styles.fieldset}>
<legend>Select plan:</legend>
<div className={styles.optionGroup}>
{plans.map((plan) => {
const uniquePlanId = `${id}-${plan.id}`;
return (
<div className={styles.option} key={plan.id}>
<input
type="radio"
name={id}
id={uniquePlanId}
value={plan.value}
onChange={() => setPlan(plan)}
/>
<label htmlFor={uniquePlanId}>
{plan.label}
</label>
</div>
);
})}
</div>
</fieldset>
</>
);
}

export default PlanSelection;

Solution:

Toonie Clicker, revisited

Earlier in the course, we created a “Toonie Clicker” game, as a way to learn about lifting state up.

Let's suppose we want to add a little “+2” that shows whenever the coin is clicked:

The markup you need has been provided. Your job is to retrigger the animation whenever the toonie is clicked.

Acceptance Criteria:

  • Clicking the toonie should show the +2 animation.
  • The animation should not show when the page originally loads. It should only show when the number of coins changes.

Code Playground

import React from 'react';

import BigCoin from './BigCoin';
import FloatingText from './FloatingText';
import styles from './App.module.css';

function App() {
const [numOfCoins, setNumOfCoins] = React.useState(0);
return (
<div className={styles.wrapper}>
<main>
<BigCoin
numOfCoins={numOfCoins}
setNumOfCoins={setNumOfCoins}
/>
<div className={styles.floatingNumWrapper}>
<FloatingText>
+2
</FloatingText>
</div>
</main>
<footer>
Your coin balance:
<strong>{numOfCoins}</strong>
</footer>
</div>
);
}

export default App;

Solution:

Stretch goal: Only showing on increment

In the real “Cookie Clicker” game, the currency that you build can be spent on tools that improve your cookie-harvesting power. This means that the # of cookies you have goes up when clicking the cookie, but goes down when buying something.

The solution we've come up with above works because the numOfCoins variable can only ever go up by 2, but what if our balance can also decrease?

In the sandbox below, we've added the ability to buy a “piggy bank” for 9 coins. Your goal is to update it so that buying a piggy bank doesn't show the FloatingText keyframe animation.

Acceptance Criteria:

  • Buying a piggy bank shouldn't re-trigger the “+2” animation.
    • Piggy banks cost 9 coins, so to test this, you need to click the toonie 5 times, and then click "Buy Piggy Bank"
  • Clicking the toonie should still show the “+2” animation
  • The “+2” animation should still not be shown when the page first loads.

Code Playground

import React from 'react';

import BigCoin from './BigCoin';
import FloatingText from './FloatingText';
import styles from './App.module.css';

const PIGGY_BANK_COST = 9;

function App() {
const [numOfCoins, setNumOfCoins] = React.useState(0);
const [numOfPiggyBanks, setNumOfPiggyBanks] = React.useState(0);
function buyPiggyBank() {
setNumOfCoins(numOfCoins - PIGGY_BANK_COST);
setNumOfPiggyBanks(numOfPiggyBanks + 1);
}
return (
<div className={styles.wrapper}>
<main>
<BigCoin
numOfCoins={numOfCoins}
setNumOfCoins={setNumOfCoins}
/>
{numOfCoins > 0 && (
<div className={styles.floatingNumWrapper}>
<FloatingText key={numOfCoins}>
+2
</FloatingText>
</div>
)}
<button
disabled={numOfCoins < PIGGY_BANK_COST}
className={styles.shopItem}
onClick={buyPiggyBank}
>
Buy Piggy Bank
{numOfPiggyBanks > 0 && (
`(${numOfPiggyBanks})`
)}
</button>
</main>
<footer>
Your coin balance:
<strong>{numOfCoins}</strong>
</footer>
</div>
);
}

export default App;

Solution:

Two notes about this:

  • In the solution video, piggy banks cost 10 coins, rather than 9. I decreased the cost after filming this video, to highlight the issue we're trying to fix. The "+2" animation is already hidden when the user has 0 coins.
  • Discord user AbiTyasTunggal came up with a solution that doesn't require a new state variable! I think I prefer it to my solution. I'll share it in the solution block below.